package com.fzq.config.security;


import com.fzq.dao.mapper.RbacPermsMapper;
import com.fzq.dao.mapper.RbacUserMapper;
import com.fzq.dao.po.RbacUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 在 Spring Security 中，UserDetailsService 的核心职责是通过用户名加载用户的认证信息 和权限信息，并返回一个实现了 UserDetails 接口的对象。这里的代码通过 new User(...) 创建一个 Spring Security 内置的 User 对象，主要目的是将业务数据封装成 Spring Security 认证所需的标准化格式。以下是详细解释：
 *
 * 1. 为什么需要 User 对象？
 * User 是 Spring Security 提供的一个内置类，它直接实现了 UserDetails 接口，用于标准化描述用户的安全信息，包括：
 *
 * 用户名（username）
 * 密码（password）
 * 权限集合（authorities）
 * 账户状态（是否启用、是否过期等）
 * Spring Security 的认证流程（如密码校验、权限检查）依赖 UserDetails 接口的实现，而 User 类已经默认处理了这些逻辑。
 *
 * 2. 为什么不直接返回自定义的 RbacUser？
 * 虽然可以自定义类实现 UserDetails 接口（例如让 RbacUser 实现 UserDetails），但在此代码中直接使用内置 User 对象的原因是：
 *
 * 简化实现：避免在 RbacUser 中手动实现 UserDetails 的所有方法（如 isAccountNonExpired、isEnabled 等）。
 * 快速适配：通过 User 的构造函数直接传递关键信息（用户名、密码、权限），无需额外处理。
 * 关注点分离：RbacUser 可能是一个纯业务实体（如 ORM 映射的数据库表对象），而安全认证信息可能需要独立的结构。
 */
@Component
public class LoginService implements UserDetailsService {

    @Autowired
    private RbacUserMapper rbacUserMapper;
    @Autowired
    private RbacPermsMapper permsMapper;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 从数据库查询业务用户对象
        RbacUser rbacUser = rbacUserMapper.selectByUsername(username);
        if (rbacUser == null) {
            throw new UsernameNotFoundException("用户名或者密码错误");
        }

        // 获取用户的权限列表（例如 ["user:read", "user:write"]）
        List<String> permsList = permsMapper.permsList(username);
        // 将权限列表转换为逗号分隔的字符串（例如 "user:read,user:write"）
        String authortys = StringUtils.join(permsList, ",");

        // 使用 Spring Security 内置的 User 类构建 UserDetails 对象
        return new User(
                username,                   // 用户名
                rbacUser.getPassword(),     // 数据库存储的加密密码
                true,                       // 账户是否启用（enabled）
                true,                       // 账户是否未过期（accountNonExpired）
                true,                       // 凭证是否未过期（credentialsNonExpired）
                true,                       // 账户是否未锁定（accountNonLocked）
                AuthorityUtils.commaSeparatedStringToAuthorityList(authortys)  // 权限集合
        );
    }
}
